<!DOCTYPE html>




<html class="theme-next gemini" lang="zh-Hans">
<head>
  <meta charset="UTF-8"/>
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1"/>
<meta name="theme-color" content="#222">



  
  
    
    
  <script src="/lib/pace/pace.min.js?v=1.0.2"></script>
  <link href="/lib/pace/pace-theme-minimal.min.css?v=1.0.2" rel="stylesheet">







<meta http-equiv="Cache-Control" content="no-transform" />
<meta http-equiv="Cache-Control" content="no-siteapp" />



  <meta name="google-site-verification" content="vjImUBDCK8Rg9G13vkIip_GUsZTtVV6s-XdSk81-jzA" />













  
  
  <link href="/lib/fancybox/source/jquery.fancybox.css?v=2.1.5" rel="stylesheet" type="text/css" />




  
  
  
  

  
    
    
  

  

  

  

  

  
    
    
    <link href="//fonts.lug.ustc.edu.cn/css?family=Lato:300,300italic,400,400italic,700,700italic&subset=latin,latin-ext" rel="stylesheet" type="text/css">
  






<link href="/lib/font-awesome/css/font-awesome.min.css?v=4.6.2" rel="stylesheet" type="text/css" />

<link href="/css/main.css?v=5.1.2" rel="stylesheet" type="text/css" />


  <meta name="keywords" content="Kotlin,Delegate,Propertie,Observable,Lazy,Map," />





  <link rel="alternate" href="/atom.xml" title="旺仔的个人博客" type="application/atom+xml" />




  <link rel="shortcut icon" type="image/x-icon" href="/favicon.png?v=5.1.2" />






<meta name="description" content="委托模式已经被证明是实现继承的一个很好的替代方式，在扩展一个基类并且重写方法时，基类就必须依赖子类的实现，当不断地修改的时候，基类就会失去当初的性质，Kotlin中就将类默认为final，确保不会被修改。 有一种模式是装饰器模式，本质就是创建一个新类，实现与基类一样的接口，并且将类的实现作为一个字段保存，这样就能在基类不被修改就能直接修改基类的实例。但是这样的缺点是会造成很多的样板代码。">
<meta name="keywords" content="Kotlin,Delegate,Propertie,Observable,Lazy,Map">
<meta property="og:type" content="article">
<meta property="og:title" content="Kotlin学习_委托模式（Delegate）和委托属性（Delegate Properties）">
<meta property="og:url" content="http://www.jowanxu.top/2017/11/22/Kotlin学习_委托模式和委托属性/index.html">
<meta property="og:site_name" content="旺仔的个人博客">
<meta property="og:description" content="委托模式已经被证明是实现继承的一个很好的替代方式，在扩展一个基类并且重写方法时，基类就必须依赖子类的实现，当不断地修改的时候，基类就会失去当初的性质，Kotlin中就将类默认为final，确保不会被修改。 有一种模式是装饰器模式，本质就是创建一个新类，实现与基类一样的接口，并且将类的实现作为一个字段保存，这样就能在基类不被修改就能直接修改基类的实例。但是这样的缺点是会造成很多的样板代码。">
<meta property="og:locale" content="zh-Hans">
<meta property="og:image" content="http://ovlhlis72.bkt.clouddn.com/17-10-25/26081326.jpg">
<meta property="og:image" content="http://ovlhlis72.bkt.clouddn.com/17-11-21/52661810.jpg">
<meta property="og:image" content="http://ovlhlis72.bkt.clouddn.com/17-11-26/37861678.jpg">
<meta property="og:image" content="http://ovlhlis72.bkt.clouddn.com/17-11-26/76088388.jpg">
<meta property="og:image" content="http://ovlhlis72.bkt.clouddn.com/17-11-26/95191798.jpg">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/1241355-ce7245d42b5e9e3f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:image" content="http://upload-images.jianshu.io/upload_images/1241355-58931b634fd12047.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240">
<meta property="og:updated_time" content="2017-11-29T00:20:35.074Z">
<meta name="twitter:card" content="summary">
<meta name="twitter:title" content="Kotlin学习_委托模式（Delegate）和委托属性（Delegate Properties）">
<meta name="twitter:description" content="委托模式已经被证明是实现继承的一个很好的替代方式，在扩展一个基类并且重写方法时，基类就必须依赖子类的实现，当不断地修改的时候，基类就会失去当初的性质，Kotlin中就将类默认为final，确保不会被修改。 有一种模式是装饰器模式，本质就是创建一个新类，实现与基类一样的接口，并且将类的实现作为一个字段保存，这样就能在基类不被修改就能直接修改基类的实例。但是这样的缺点是会造成很多的样板代码。">
<meta name="twitter:image" content="http://ovlhlis72.bkt.clouddn.com/17-10-25/26081326.jpg">



<script type="text/javascript" id="hexo.configurations">
  var NexT = window.NexT || {};
  var CONFIG = {
    root: '/',
    scheme: 'Gemini',
    sidebar: {"position":"left","display":"post","offset":12,"offset_float":12,"b2t":false,"scrollpercent":false,"onmobile":false},
    fancybox: true,
    tabs: true,
    motion: false,
    duoshuo: {
      userId: '0',
      author: '博主'
    },
    algolia: {
      applicationID: '',
      apiKey: '',
      indexName: '',
      hits: {"per_page":10},
      labels: {"input_placeholder":"Search for Posts","hits_empty":"We didn't find any results for the search: ${query}","hits_stats":"${hits} results found in ${time} ms"}
    }
  };
</script>



  <link rel="canonical" href="http://www.jowanxu.top/2017/11/22/Kotlin学习_委托模式和委托属性/"/>





  <title>Kotlin学习_委托模式（Delegate）和委托属性（Delegate Properties） | 旺仔的个人博客</title>
  














</head>

<body itemscope itemtype="http://schema.org/WebPage" lang="zh-Hans">

  
  
    
  

  <div class="container sidebar-position-left page-post-detail ">
    <div class="headband"></div>
    <a href="https://github.com/wangzailfm"><img style="position: absolute; top: 0; right: 0; border: 0;" src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png"></a>

    <header id="header" class="header" itemscope itemtype="http://schema.org/WPHeader">
      <div class="header-inner"><div class="site-brand-wrapper">
  <div class="site-meta ">
    

    <div class="custom-logo-site-title">
      <a href="/"  class="brand" rel="start">
        <span class="logo-line-before"><i></i></span>
        <span class="site-title">旺仔的个人博客</span>
        <span class="logo-line-after"><i></i></span>
      </a>
    </div>
      
        <p class="site-subtitle">叫我旺仔<br/>Android Developer</p>
      
  </div>

  <div class="site-nav-toggle">
    <button>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
      <span class="btn-bar"></span>
    </button>
  </div>
</div>

<nav class="site-nav">
  

  
    <ul id="menu" class="menu">
      
        
        <li class="menu-item menu-item-home">
          <a href="/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-home"></i> <br />
            
            首页
          </a>
        </li>
      
        
        <li class="menu-item menu-item-categories">
          <a href="/categories/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-th"></i> <br />
            
            分类
          </a>
        </li>
      
        
        <li class="menu-item menu-item-about">
          <a href="/about/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-user"></i> <br />
            
            关于
          </a>
        </li>
      
        
        <li class="menu-item menu-item-archives">
          <a href="/archives/" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-archive"></i> <br />
            
            归档
          </a>
        </li>
      
        
        <li class="menu-item menu-item-tags">
          <a href="/tags" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-tags"></i> <br />
            
            标签
          </a>
        </li>
      
        
        <li class="menu-item menu-item-commonweal">
          <a href="/404.html" rel="section">
            
              <i class="menu-item-icon fa fa-fw fa-heartbeat"></i> <br />
            
            公益
          </a>
        </li>
      

      
        <li class="menu-item menu-item-search">
          
            <a href="javascript:;" class="popup-trigger">
          
            
              <i class="menu-item-icon fa fa-search fa-fw"></i> <br />
            
            搜索
          </a>
        </li>
      
    </ul>
  

  
    <div class="site-search">
      
  <div class="popup search-popup local-search-popup">
  <div class="local-search-header clearfix">
    <span class="search-icon">
      <i class="fa fa-search"></i>
    </span>
    <span class="popup-btn-close">
      <i class="fa fa-times-circle"></i>
    </span>
    <div class="local-search-input-wrapper">
      <input autocomplete="off"
             placeholder="搜索..." spellcheck="false"
             type="text" id="local-search-input">
    </div>
  </div>
  <div id="local-search-result"></div>
</div>



    </div>
  
</nav>



 </div>
    </header>

    <main id="main" class="main">
      <div class="main-inner">
        <div class="content-wrap">
          <div id="content" class="content">
            

  <div id="posts" class="posts-expand">
    

  

  
  
  

  <article class="post post-type-normal" itemscope itemtype="http://schema.org/Article">
  
  
  
  <div class="post-block">
    <link itemprop="mainEntityOfPage" href="http://www.jowanxu.top/2017/11/22/Kotlin学习_委托模式和委托属性/">

    <span hidden itemprop="author" itemscope itemtype="http://schema.org/Person">
      <meta itemprop="name" content="Jowan">
      <meta itemprop="description" content="">
      <meta itemprop="image" content="/images/avatar.gif">
    </span>

    <span hidden itemprop="publisher" itemscope itemtype="http://schema.org/Organization">
      <meta itemprop="name" content="旺仔的个人博客">
    </span>

    
      <header class="post-header">

        
        
          <h1 class="post-title" itemprop="name headline">Kotlin学习_委托模式（Delegate）和委托属性（Delegate Properties）</h1>
        

        <div class="post-meta">
          <span class="post-time">
            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-o"></i>
              </span>
              
                <span class="post-meta-item-text">发表于</span>
              
              <time title="创建于" itemprop="dateCreated datePublished" datetime="2017-11-22T08:30:12+08:00">
                2017-11-22
              </time>
            

            
              <span class="post-meta-divider">|</span>
            

            
              <span class="post-meta-item-icon">
                <i class="fa fa-calendar-check-o"></i>
              </span>
              
                <span class="post-meta-item-text">更新于</span>
              
              <time title="更新于" itemprop="dateModified" datetime="2017-11-29T08:20:35+08:00">
                2017-11-29
              </time>
            
          </span>

          
            <span class="post-category" >
            
              <span class="post-meta-divider">|</span>
            
              <span class="post-meta-item-icon">
                <i class="fa fa-folder-o"></i>
              </span>
              
                <span class="post-meta-item-text">分类于</span>
              
              
                <span itemprop="about" itemscope itemtype="http://schema.org/Thing">
                  <a href="/categories/Kotlin/" itemprop="url" rel="index">
                    <span itemprop="name">Kotlin</span>
                  </a>
                </span>

                
                
              
            </span>
          

          
            
          

          
          

          
            <span class="post-meta-divider">|</span>
            <span class="page-pv"><i class="fa fa-file-o"> 文章热度</i>
            <span class="busuanzi-value" id="busuanzi_value_page_pv" ></span>°C
            </span>
          

          
            <br/>
            <div class="post-wordcount">
              
                
                <span class="post-meta-item-icon">
                  <i class="fa fa-file-word-o"></i>
                </span>
                
                  <span class="post-meta-item-text">文章字数</span>
                
                <span title="文章字数">
                  3,633 字
                </span>
              

              
                <span class="post-meta-divider">|</span>
              

              
                <span class="post-meta-item-icon">
                  <i class="fa fa-clock-o"></i>
                </span>
                
                  <span class="post-meta-item-text">阅读时长需</span>
                
                <span title="阅读时长需">
                  16 分钟
                </span>
              
            </div>
          

          

        </div>
      </header>
    

    
    
    
    <div class="post-body" itemprop="articleBody">

      
      

      
        <p><img src="http://ovlhlis72.bkt.clouddn.com/17-10-25/26081326.jpg" alt="Tooling"></p>
<p>委托模式已经被证明是实现继承的一个很好的替代方式，在扩展一个基类并且重写方法时，基类就必须依赖子类的实现，当不断地修改的时候，基类就会失去当初的性质，Kotlin中就将类默认为<code>final</code>，确保不会被修改。</p>
<p>有一种模式是装饰器模式，本质就是创建一个新类，实现与基类一样的接口，并且将类的实现作为一个字段保存，这样就能在基类不被修改就能直接修改基类的实例。但是这样的缺点是会造成很多的样板代码。</p>
<a id="more"></a>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">DelegatingCollection</span>&lt;<span class="type">T</span>&gt; : <span class="type">Collection</span>&lt;<span class="type">T</span>&gt; </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">val</span> innerList = mutableListOf&lt;T&gt;()</div><div class="line">    <span class="keyword">override</span> <span class="keyword">val</span> size: <span class="built_in">Int</span></div><div class="line">        <span class="keyword">get</span>() = innerList.size</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">contains</span><span class="params">(element: <span class="type">T</span>)</span></span>: <span class="built_in">Boolean</span> = innerList.contains(element)</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">containsAll</span><span class="params">(elements: <span class="type">Collection</span>&lt;<span class="type">T</span>&gt;)</span></span>: <span class="built_in">Boolean</span> = innerList.addAll(elements)</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">isEmpty</span><span class="params">()</span></span>: <span class="built_in">Boolean</span> = innerList.isEmpty()</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">iterator</span><span class="params">()</span></span>: Iterator&lt;T&gt; = innerList.iterator()</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>当你实现<code>Collection</code>接口的时候，需要重写这几个方法，这里面的代码量是很多的，但是如果用了委托，那么代码就是这样的</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">DelegatingCollection2</span>&lt;<span class="type">T</span>&gt;</span>(innerList: Collection&lt;T&gt; = mutableListOf&lt;T&gt;()) : Collection&lt;T&gt; <span class="keyword">by</span> innerList</div></pre></td></tr></table></figure>
<p>这么简单？就能实现那几个方法？我们来看一下生成的代码</p>
<p><img src="http://ovlhlis72.bkt.clouddn.com/17-11-21/52661810.jpg" alt=""></p>
<p>是不是省去了很多手写的代码量，下面我们来介绍这种属性。</p>
<h2 id="委托模式-Delegate"><a href="#委托模式-Delegate" class="headerlink" title="委托模式(Delegate)"></a>委托模式(Delegate)</h2><p>Kotlin支持委托模式，是允许对象组合实现与继承相同的代码复用的，简单来说就是操作的对象不用自己去执行，而是将任务交给另一个对象操作，这样的模式就叫委托模式，被操作的对象叫<strong>委托</strong>。</p>
<p>委托模式是有两个对象参与处理同一个请求，接受请求的对象将请求委托给另一个对象来处理。</p>
<h3 id="类委托"><a href="#类委托" class="headerlink" title="类委托"></a>类委托</h3><p>同样我们用上面集合的栗子，现在我们已经是委托到一个对象了，如果我们要修改集合里面的方法的时候，可以直接重写，而不用重复的去写新的方法，下面我们来在一个集合里面插入数据，并且获取插入的次数。</p>
<p>下面代码是默认实现<code>MutableCollection</code>接口，获取插入的次数<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">DefaultCollection</span>&lt;<span class="type">T</span>&gt; : <span class="type">MutableCollection</span>&lt;<span class="type">T</span>&gt; </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">val</span> innerList = mutableListOf&lt;T&gt;()</div><div class="line">    <span class="keyword">private</span> <span class="keyword">var</span> addedSum = <span class="number">0</span></div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">add</span><span class="params">(element: <span class="type">T</span>)</span></span>: <span class="built_in">Boolean</span> &#123;</div><div class="line">        addedSum++</div><div class="line">        <span class="keyword">return</span> innerList.add(element)</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">addAll</span><span class="params">(elements: <span class="type">Collection</span>&lt;<span class="type">T</span>&gt;)</span></span>: <span class="built_in">Boolean</span> &#123;</div><div class="line">        addedSum += elements.size</div><div class="line">        <span class="keyword">return</span> innerList.addAll(elements)</div><div class="line">    &#125;</div><div class="line">    <span class="keyword">override</span> <span class="keyword">val</span> size: <span class="built_in">Int</span></div><div class="line">        <span class="keyword">get</span>() = innerList.size</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">contains</span><span class="params">(element: <span class="type">T</span>)</span></span>: <span class="built_in">Boolean</span> = innerList.contains(element)</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">containsAll</span><span class="params">(elements: <span class="type">Collection</span>&lt;<span class="type">T</span>&gt;)</span></span>: <span class="built_in">Boolean</span> = innerList.addAll(elements)</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">isEmpty</span><span class="params">()</span></span>: <span class="built_in">Boolean</span> = innerList.isEmpty()</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">iterator</span><span class="params">()</span></span>: MutableIterator&lt;T&gt; = innerList.iterator()</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">clear</span><span class="params">()</span></span> = innerList.clear()</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">remove</span><span class="params">(element: <span class="type">T</span>)</span></span>: <span class="built_in">Boolean</span> = innerList.remove(element)</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">removeAll</span><span class="params">(elements: <span class="type">Collection</span>&lt;<span class="type">T</span>&gt;)</span></span>: <span class="built_in">Boolean</span> = innerList.removeAll(elements)</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">retainAll</span><span class="params">(elements: <span class="type">Collection</span>&lt;<span class="type">T</span>&gt;)</span></span>: <span class="built_in">Boolean</span> &#123;</div><div class="line">        TODO(<span class="string">"not implemented"</span>) <span class="comment">//To change body of created functions use File | Settings | File Templates.</span></div><div class="line">    &#125;</div><div class="line"></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>实现类委托<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">DelegatingCollection3</span>&lt;<span class="type">T</span>&gt;</span>(<span class="keyword">private</span> <span class="keyword">val</span> innerList: MutableCollection&lt;T&gt; = HashSet&lt;T&gt;()) : MutableCollection&lt;T&gt; <span class="keyword">by</span> innerList &#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">var</span> addedSum = <span class="number">0</span></div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">add</span><span class="params">(element: <span class="type">T</span>)</span></span>: <span class="built_in">Boolean</span> &#123;</div><div class="line">        addedSum++</div><div class="line">        <span class="keyword">return</span> innerList.add(element)</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">addAll</span><span class="params">(elements: <span class="type">Collection</span>&lt;<span class="type">T</span>&gt;)</span></span>: <span class="built_in">Boolean</span> &#123;</div><div class="line">        addedSum += elements.size</div><div class="line">        <span class="keyword">return</span> innerList.addAll(elements)</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>是不是省去很多无用的代码，只需要重写我们需要的方法<code>add</code>和<code>addAll</code>，其他没有写出来的方法全部都交给委托来实现。</p>
<p>而且没有对底层集合的实现方法引入任何的依赖，所以对被调用的操作具有完全的控制，如不用担心集合是不是通过循环中调用<code>add</code>来实现<code>addAll</code>。</p>
<h2 id="委托属性-Delegate-Properties"><a href="#委托属性-Delegate-Properties" class="headerlink" title="委托属性(Delegate Properties)"></a>委托属性(Delegate Properties)</h2><p>有一种属性，在使用的时候每次都要手动实现它，但是可以做到只实现一次，并且放到库中，一直使用，这种属性称为委托属性。<br>委托属性包括：</p>
<ul>
<li>延迟属性(lazy properties)：数据只在第一次被访问的时候计算。</li>
<li>可观察属性(observable properties)：监听得到属性变化通知。</li>
<li><code>Map</code>委托属性(Storing Properties in a Map)：将所有属性存在<code>Map</code>中。</li>
</ul>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Foo</span> </span>&#123;</div><div class="line">    <span class="keyword">var</span> p: String <span class="keyword">by</span> Delegate()</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>委托模式的语法是<code>val/var &lt;property name&gt;: &lt;Type&gt; by &lt;expression&gt;</code>在<code>by</code>后面的<code>expression</code>就是委托的部分，会将属性的<code>get()</code>和<code>set()</code>委托给<code>getValue()</code>和<code>setValue()</code>方法。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Foo</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">val</span> delegate = Delegate()</div><div class="line"></div><div class="line">    <span class="keyword">var</span> p: String</div><div class="line">        <span class="keyword">set</span>(value: String) = delegate.setValue(..., value)</div><div class="line">        <span class="keyword">get</span>() = delegate.getValue(...)</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>委托属性不需要实现任何的接口，但是要提供<code>getValue()</code>方法(如果是<code>var</code>的话要提供<code>setValue()</code>方法)，方法前加<code>operator</code>关键字。</p>
<p>下面是一个自定义的<code>Delegate</code>类：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Delegate</span> </span>&#123;</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">getValue</span><span class="params">(thisRef: <span class="type">Any</span>?, property: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: String &#123;</div><div class="line">        <span class="keyword">return</span> <span class="string">"<span class="variable">$thisRef</span>, thank you for delegating '<span class="subst">$&#123;property.name&#125;</span>' to me!"</span></div><div class="line">    &#125;</div><div class="line"> </div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">setValue</span><span class="params">(thisRef: <span class="type">Any</span>?, property: <span class="type">KProperty</span>&lt;*&gt;, value: <span class="type">String</span>)</span></span> &#123;</div><div class="line">        println(<span class="string">"<span class="variable">$value</span> has been assigned to '<span class="subst">$&#123;property.name&#125;</span> in <span class="variable">$thisRef</span>.'"</span>)</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>当从委托属性<code>p</code>获取到<code>Deletage</code>的的实例时，<code>Deletage</code>的<code>getValue</code>就会被调用，<code>getValue</code>函数中的第一个参数就是<code>p</code>获取到的实例，第二个参数就是属性<code>p</code>。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">val</span> e = Example()</div><div class="line">println(e.p)</div></pre></td></tr></table></figure>
<p>打印出来的内容是：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line"><span class="symbol">Example@</span><span class="number">33</span>a17727, thank you <span class="keyword">for</span> delegating ‘p’ to me!</div></pre></td></tr></table></figure>
<p>由于<code>p</code>是<code>var</code>类型的，所有可以调用<code>setValue</code>函数，前两个参数与<code>getValue</code>参数一样，第三个就是要赋予的值：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">e.p = <span class="string">"NEW"</span></div></pre></td></tr></table></figure>
<p>这下打印出来的内容就是：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div></pre></td><td class="code"><pre><div class="line">NEW has been assigned to ‘p’ <span class="keyword">in</span> <span class="symbol">Example@</span><span class="number">33</span>a17727.</div></pre></td></tr></table></figure>
<p><strong>注意：自 Kotlin1.1起可以在函数或代码块中声明一个委托属性，因此委托属性不一定是类的成员</strong></p>
<h3 id="委托标准"><a href="#委托标准" class="headerlink" title="委托标准"></a>委托标准</h3><p>Kotlin的标准库中对于一些有用的委托提供了工厂(Factory)方法，这些接口在Kotlin标准库中声明。<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">interface</span> <span class="title">ReadOnlyProperty</span>&lt;<span class="type">in R, out T</span>&gt; </span>&#123;</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">getValue</span><span class="params">(thisRef: <span class="type">R</span>, property: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: T</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">interface</span> <span class="title">ReadWriteProperty</span>&lt;<span class="type">in R, T</span>&gt; </span>&#123;</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">getValue</span><span class="params">(thisRef: <span class="type">R</span>, property: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: T</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">setValue</span><span class="params">(thisRef: <span class="type">R</span>, property: <span class="type">KProperty</span>&lt;*&gt;, value: <span class="type">T</span>)</span></span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h4 id="延迟属性-Lazy"><a href="#延迟属性-Lazy" class="headerlink" title="延迟属性 Lazy"></a>延迟属性 <code>Lazy</code></h4><p><img src="http://ovlhlis72.bkt.clouddn.com/17-11-26/37861678.jpg" alt=""></p>
<p>函数<code>lazy()</code>接收一个Lambdas表达式，然后并返回一个<code>Lazy &lt;T&gt;</code>的实例，它可以作为实现<code>lazy</code>属性的委托：第一次调用<code>get()</code>函数的时候会向执行Lambdas传递到<code>lazy()</code>函数，并且保存结果，后面调用的<code>get()</code>函数会直接返回报错的结果。</p>
<p>首先我们来看一个栗子，里面先不用到<code>lazy</code>，我们来看如何<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">loadName</span><span class="params">(person: <span class="type">Person</span>)</span></span>: String &#123;</div><div class="line">    println(<span class="string">"Load Name for <span class="subst">$&#123;person.name&#125;</span>"</span>)</div><div class="line">    <span class="keyword">return</span> person.name</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">loadAge</span><span class="params">(person: <span class="type">Person</span>)</span></span>: <span class="built_in">Int</span> &#123;</div><div class="line">    println(<span class="string">"Load Age for <span class="subst">$&#123;person.age&#125;</span>"</span>)</div><div class="line">    <span class="keyword">return</span> person.age</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span></span>(<span class="keyword">val</span> name: String, <span class="keyword">val</span> age: <span class="built_in">Int</span>) &#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">var</span> _names: String? = <span class="literal">null</span></div><div class="line">    <span class="keyword">val</span> newName: String</div><div class="line">        <span class="keyword">get</span>() &#123;</div><div class="line">            <span class="keyword">if</span> (_names == <span class="literal">null</span>) &#123;</div><div class="line">                _names = loadName(<span class="keyword">this</span>)</div><div class="line">            &#125;</div><div class="line">            <span class="keyword">return</span> _names!!</div><div class="line">        &#125;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">var</span> _ages: <span class="built_in">Int</span>? = <span class="literal">null</span></div><div class="line">    <span class="keyword">val</span> newAge: <span class="built_in">Int</span></div><div class="line">        <span class="keyword">get</span>() &#123;</div><div class="line">            <span class="keyword">if</span> (_ages == <span class="literal">null</span>) &#123;</div><div class="line">                _ages = loadAge(<span class="keyword">this</span>)</div><div class="line">            &#125;</div><div class="line">            <span class="keyword">return</span> _ages!!</div><div class="line">        &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">(args: <span class="type">Array</span>&lt;<span class="type">String</span>&gt;)</span></span> &#123;</div><div class="line">    <span class="keyword">val</span> p = Person(<span class="string">"Alice"</span>, <span class="number">23</span>)</div><div class="line">    p.newName.println()</div><div class="line">    p.newName.println()</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>首先先判断<code>_names</code>是否为空，然后通过一个方法，里面进行了一些操作，来赋予<code>_names</code>值，最后<code>newName</code>的值即为<code>_names</code>。<br>打印的内容：</p>
<p><img src="http://ovlhlis72.bkt.clouddn.com/17-11-26/76088388.jpg" alt=""></p>
<p>那么如果我们用<code>lazy</code>来代替这种写法会是什么样的呢？</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">loadName</span><span class="params">(person: <span class="type">Person</span>)</span></span>: String &#123; </div><div class="line">    <span class="comment">/*代码与上面一样*/</span></div><div class="line">&#125;</div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">loadAge</span><span class="params">(person: <span class="type">Person</span>)</span></span>: <span class="built_in">Int</span> &#123; </div><div class="line">    <span class="comment">/*代码与上面一样*/</span></div><div class="line">&#125;</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span></span>(<span class="keyword">val</span> name: String) &#123;</div><div class="line">    <span class="keyword">val</span> newName <span class="keyword">by</span> lazy &#123; loadName(<span class="keyword">this</span>) &#125;</div><div class="line">    <span class="keyword">val</span> newAge <span class="keyword">by</span> lazy &#123; loadAge(<span class="keyword">this</span>) &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">(args: <span class="type">Array</span>&lt;<span class="type">String</span>&gt;)</span></span> &#123;</div><div class="line">    <span class="comment">/*代码与上面一样*/</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>打印出来的内容，和上面是一模一样的。</p>
<p>对比一下，当我们的属性越来越多，那么重复的代码也就越来越多，使用<code>lazy</code>省去了很多多余的代码。</p>
<p><img src="http://ovlhlis72.bkt.clouddn.com/17-11-26/95191798.jpg" alt=""></p>
<p>默认地，对于<code>lazy</code>属性的计算是加了同步锁（<code>synchronized</code>） 的： 这个值只在一个线程被计算，并且所有的线程会看到相同的值。<br>如果要将同步锁关闭，可以多个线程同步执行，就加<code>LazyThreadSafetyMode.PUBLICATION</code>参数即可：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">val</span> lazyValue: String <span class="keyword">by</span> lazy(LazyThreadSafetyMode.PUBLICATION) &#123;</div><div class="line">    println(<span class="string">"computed!"</span>)</div><div class="line">    <span class="string">"Hello"</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>如果要关掉线程安全配置，就加<code>LazyThreadSafetyMode.NONE</code>参数即可：<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">val</span> lazyValue: String <span class="keyword">by</span> lazy(LazyThreadSafetyMode.NONE) &#123;</div><div class="line">    println(<span class="string">"computed!"</span>)</div><div class="line">    <span class="string">"Hello"</span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h4 id="可观察属性-Observable"><a href="#可观察属性-Observable" class="headerlink" title="可观察属性 Observable"></a>可观察属性 <code>Observable</code></h4><p><code>Delegates.observable()</code>有两个参数：初始化值和<code>handler</code>，每次对属性赋值操作，都会回调该handler方法（在属性赋值后执行），该方法里面有三个参数，分别是：被赋值的属性，旧值和新值。<br>举个例子：<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> kotlin.properties.Delegates</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</div><div class="line">    <span class="keyword">var</span> name: String <span class="keyword">by</span> Delegates.observable(<span class="string">"&lt;no name&gt;"</span>) &#123;</div><div class="line">        prop, old, new -&gt;</div><div class="line">        println(<span class="string">"<span class="variable">$old</span> -&gt; <span class="variable">$new</span>"</span>)</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">(args: <span class="type">Array</span>&lt;<span class="type">String</span>&gt;)</span></span> &#123;</div><div class="line">    <span class="keyword">val</span> user = User()</div><div class="line">    user.name = <span class="string">"first"</span></div><div class="line">    user.name = <span class="string">"second"</span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>在<code>User</code>类中，<code>&lt;no name&gt;</code>就是初始化值，<code>{}</code>包住的代码块就是<code>handler</code>方法，<code>pro, old, new</code>就是该方法的三个参数，打印出来的内容为：<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div></pre></td><td class="code"><pre><div class="line">&lt;no name&gt; -&gt; first</div><div class="line">first -&gt; second</div></pre></td></tr></table></figure></p>
<p>如果需要拦截修改属性值动作并禁止修改，可以使用<code>vetoable()</code>取代<code>observable()</code>，<code>handler</code>需要返回一个<code>Boolean</code>，<code>true</code>表示同意修改，<code>false</code>表示禁止修改，该回调会在属性值修改前调用。<br>将上面的例子里面的<code>observable()</code>修改为<code>vetoable()</code>后：<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">import</span> kotlin.properties.Delegates</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">User</span> </span>&#123;</div><div class="line">    <span class="keyword">var</span> name: String <span class="keyword">by</span> Delegates.vetoable(<span class="string">"&lt;no name&gt;"</span>) &#123;</div><div class="line">        prop, old, new -&gt;</div><div class="line">        println(<span class="string">"<span class="variable">$old</span> -&gt; <span class="variable">$new</span>"</span>)</div><div class="line">        <span class="literal">false</span> </div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">(args: <span class="type">Array</span>&lt;<span class="type">String</span>&gt;)</span></span> &#123;</div><div class="line">    <span class="keyword">val</span> user = User()</div><div class="line">    user.name = <span class="string">"first"</span></div><div class="line">    user.name = <span class="string">"second"</span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>打印的结果是：</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1241355-ce7245d42b5e9e3f.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="false"></p>
<p>如果改为<code>true</code>，那就更<code>observable()</code>打印的一样了：</p>
<p><img src="http://upload-images.jianshu.io/upload_images/1241355-58931b634fd12047.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240" alt="true"></p>
<h4 id="Map委托属性-Storing-Properties-in-a-Map"><a href="#Map委托属性-Storing-Properties-in-a-Map" class="headerlink" title="Map委托属性(Storing Properties in a Map)"></a><code>Map</code>委托属性(Storing Properties in a Map)</h4><p>可以用<code>Map</code>作为委托用于委托属性，多用于<code>JSON</code>解析上。</p>
<p>下面举个栗子，一个类里面有一个<code>Map</code>存放一些属性，通过<code>setAttribute</code>来设置这些属性：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person</span> </span>&#123;</div><div class="line">    <span class="keyword">private</span> <span class="keyword">val</span> _attributes = hashMapOf&lt;String, String&gt;()</div><div class="line">    <span class="function"><span class="keyword">fun</span> <span class="title">setAttribute</span><span class="params">(attrName: <span class="type">String</span>, value: <span class="type">String</span>)</span></span> &#123;</div><div class="line">        _attributes[attrName] = value</div><div class="line">    &#125;</div><div class="line">    <span class="comment">// 获取键值为name的值</span></div><div class="line">    <span class="keyword">val</span> name: String</div><div class="line">        <span class="keyword">get</span>() = _attributes[<span class="string">"name"</span>]!!</div><div class="line">    <span class="comment">// 获取键值为company的值</span></div><div class="line">    <span class="keyword">val</span> company: String</div><div class="line">        <span class="keyword">get</span>() = _attributes[<span class="string">"company"</span>]!!</div><div class="line">    <span class="comment">// 获取键值为address的值</span></div><div class="line">    <span class="keyword">val</span> address: String</div><div class="line">        <span class="keyword">get</span>() = _attributes[<span class="string">"address"</span>]!!</div><div class="line">    <span class="comment">// 获取键值为email的值</span></div><div class="line">    <span class="keyword">val</span> email: String</div><div class="line">        <span class="keyword">get</span>() = _attributes[<span class="string">"email"</span>]!!</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">(args: <span class="type">Array</span>&lt;<span class="type">String</span>&gt;)</span></span> &#123;</div><div class="line">    <span class="keyword">val</span> p = Person()</div><div class="line">    <span class="keyword">val</span> <span class="keyword">data</span> = mapOf(<span class="string">"name"</span> to <span class="string">"Dmitry"</span>, <span class="string">"company"</span> to <span class="string">"JetBrains"</span>)</div><div class="line">    <span class="keyword">for</span> ((attrName, value) <span class="keyword">in</span> <span class="keyword">data</span>)</div><div class="line">        p.setAttribute(attrName, value)</div><div class="line">    println(p.name) <span class="comment">// 打印Dmitry</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>然后我们将这些属性委托给<code>Map</code>，再将代码简写一下<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Person2</span></span>(<span class="keyword">private</span> <span class="keyword">val</span> attributes: Map&lt;String, String&gt;) &#123;</div><div class="line">    <span class="keyword">val</span> name: String <span class="keyword">by</span>  attributes</div><div class="line">    <span class="keyword">val</span> company: String <span class="keyword">by</span>  attributes</div><div class="line">    <span class="keyword">val</span> address: String <span class="keyword">by</span>  attributes</div><div class="line">    <span class="keyword">val</span> email: String <span class="keyword">by</span>  attributes</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">(args: <span class="type">Array</span>&lt;<span class="type">String</span>&gt;)</span></span> &#123;</div><div class="line">    <span class="keyword">val</span> <span class="keyword">data</span> = mapOf(<span class="string">"name"</span> to <span class="string">"Dmitry"</span>, <span class="string">"company"</span> to <span class="string">"JetBrains"</span>)</div><div class="line">    <span class="keyword">val</span> p = Person2(<span class="keyword">data</span>)</div><div class="line">    println(p.name) <span class="comment">// Dmitry</span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>同样对比，省去重复代码，我们来看一下生成的代码是什么样子的：</p>
<figure class="highlight java"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div><div class="line">37</div><div class="line">38</div><div class="line">39</div><div class="line">40</div><div class="line">41</div><div class="line">42</div><div class="line">43</div><div class="line">44</div><div class="line">45</div><div class="line">46</div><div class="line">47</div><div class="line">48</div><div class="line">49</div><div class="line">50</div><div class="line">51</div></pre></td><td class="code"><pre><div class="line"><span class="keyword">public</span> <span class="keyword">final</span> <span class="class"><span class="keyword">class</span> <span class="title">Person2</span> </span>&#123;</div><div class="line">   <span class="comment">// $FF: synthetic field</span></div><div class="line">   <span class="keyword">static</span> <span class="keyword">final</span> KProperty[] $$delegatedProperties = <span class="keyword">new</span> KProperty[]&#123;(KProperty)Reflection.property1(<span class="keyword">new</span> PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person2.class), <span class="string">"name"</span>, <span class="string">"getName()Ljava/lang/String;"</span>)), (KProperty)Reflection.property1(<span class="keyword">new</span> PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person2.class), <span class="string">"company"</span>, <span class="string">"getCompany()Ljava/lang/String;"</span>)), (KProperty)Reflection.property1(<span class="keyword">new</span> PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person2.class), <span class="string">"address"</span>, <span class="string">"getAddress()Ljava/lang/String;"</span>)), (KProperty)Reflection.property1(<span class="keyword">new</span> PropertyReference1Impl(Reflection.getOrCreateKotlinClass(Person2.class), <span class="string">"email"</span>, <span class="string">"getEmail()Ljava/lang/String;"</span>))&#125;;</div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> Map name$delegate;</div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> Map company$delegate;</div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> Map address$delegate;</div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> Map email$delegate;</div><div class="line">   <span class="keyword">private</span> <span class="keyword">final</span> Map attributes;</div><div class="line"></div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">getName</span><span class="params">()</span> </span>&#123;</div><div class="line">      Map var1 = <span class="keyword">this</span>.name$delegate;</div><div class="line">      KProperty var3 = $$delegatedProperties[<span class="number">0</span>];</div><div class="line">      <span class="keyword">return</span> (String)MapsKt.getOrImplicitDefaultNullable(var1, var3.getName());</div><div class="line">   &#125;</div><div class="line"></div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">getCompany</span><span class="params">()</span> </span>&#123;</div><div class="line">      Map var1 = <span class="keyword">this</span>.company$delegate;</div><div class="line">      KProperty var3 = $$delegatedProperties[<span class="number">1</span>];</div><div class="line">      <span class="keyword">return</span> (String)MapsKt.getOrImplicitDefaultNullable(var1, var3.getName());</div><div class="line">   &#125;</div><div class="line"></div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">getAddress</span><span class="params">()</span> </span>&#123;</div><div class="line">      Map var1 = <span class="keyword">this</span>.address$delegate;</div><div class="line">      KProperty var3 = $$delegatedProperties[<span class="number">2</span>];</div><div class="line">      <span class="keyword">return</span> (String)MapsKt.getOrImplicitDefaultNullable(var1, var3.getName());</div><div class="line">   &#125;</div><div class="line"></div><div class="line">   <span class="meta">@NotNull</span></div><div class="line">   <span class="function"><span class="keyword">public</span> <span class="keyword">final</span> String <span class="title">getEmail</span><span class="params">()</span> </span>&#123;</div><div class="line">      Map var1 = <span class="keyword">this</span>.email$delegate;</div><div class="line">      KProperty var3 = $$delegatedProperties[<span class="number">3</span>];</div><div class="line">      <span class="keyword">return</span> (String)MapsKt.getOrImplicitDefaultNullable(var1, var3.getName());</div><div class="line">   &#125;</div><div class="line"></div><div class="line">   <span class="function"><span class="keyword">public</span> <span class="title">Person2</span><span class="params">(@NotNull Map attributes)</span> </span>&#123;</div><div class="line">      Intrinsics.checkParameterIsNotNull(attributes, <span class="string">"attributes"</span>);</div><div class="line">      <span class="keyword">super</span>();</div><div class="line">      <span class="keyword">this</span>.attributes = attributes;</div><div class="line">      <span class="keyword">this</span>.name$delegate = <span class="keyword">this</span>.attributes;</div><div class="line">      <span class="keyword">this</span>.company$delegate = <span class="keyword">this</span>.attributes;</div><div class="line">      <span class="keyword">this</span>.address$delegate = <span class="keyword">this</span>.attributes;</div><div class="line">      <span class="keyword">this</span>.email$delegate = <span class="keyword">this</span>.attributes;</div><div class="line">   &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h2 id="局部委托属性（1-1-起）"><a href="#局部委托属性（1-1-起）" class="headerlink" title="局部委托属性（1.1 起）"></a>局部委托属性（1.1 起）</h2><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div></pre></td><td class="code"><pre><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">main</span><span class="params">(args: <span class="type">Array</span>&lt;<span class="type">String</span>&gt;)</span></span> &#123;</div><div class="line">    example(<span class="string">"localDelegate"</span>)</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="title">example</span><span class="params">(value: <span class="type">String</span>)</span></span> &#123;</div><div class="line">    <span class="keyword">val</span> localDelegate <span class="keyword">by</span> lazy &#123;</div><div class="line">        print(<span class="string">"first "</span>)</div><div class="line">        value</div><div class="line">    &#125;</div><div class="line">    localDelegate.println() <span class="comment">// 打印first localDelegate</span></div><div class="line">    localDelegate.println() <span class="comment">// 打印localDelegate</span></div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>现在，Kotlin支持局部委托属性。</p>
<h2 id="委托属性要求"><a href="#委托属性要求" class="headerlink" title="委托属性要求"></a>委托属性要求</h2><p>下面的代码是个委托类<code>Delegate</code>，里面有两个函数，一个是<code>getValue</code>函数，一个是<code>setValue</code>函数。</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Delegate</span> </span>&#123;</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">getValue</span><span class="params">(thisRef: <span class="type">Any</span>?, property: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: String &#123;</div><div class="line">        <span class="keyword">return</span> <span class="string">"<span class="variable">$thisRef</span>, thank you for delegating '<span class="subst">$&#123;property.name&#125;</span>' to me!"</span></div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">setValue</span><span class="params">(thisRef: <span class="type">Any</span>?, property: <span class="type">KProperty</span>&lt;*&gt;, value: <span class="type">String</span>)</span></span> &#123;</div><div class="line">        println(<span class="string">"<span class="variable">$value</span> has been assigned to '<span class="subst">$&#123;property.name&#125;</span> in <span class="variable">$thisRef</span>.'"</span>)</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<h3 id="只读属性（read-only，使用val定义）"><a href="#只读属性（read-only，使用val定义）" class="headerlink" title="只读属性（read-only，使用val定义）"></a>只读属性（<code>read-only</code>，使用<code>val</code>定义）</h3><p>委托类需提供<code>getValue</code>函数，参数要求：</p>
<ul>
<li><code>thisRef</code>：第一个参数，必须是属性对应的类或父类型。(上面的<code>thisRef: Any?</code>)</li>
<li><code>property</code>：第二个参数，必须是“KProperty&lt;<em>&gt;”或它的父类型(上面的`property: KProperty&lt;</em>&gt;`)。</li>
<li>函数返回类型必须跟属性同类型（或者子类型）。</li>
</ul>
<h3 id="可变属性（mutable，使用var定义）"><a href="#可变属性（mutable，使用var定义）" class="headerlink" title="可变属性（mutable，使用var定义）"></a>可变属性（<code>mutable</code>，使用<code>var</code>定义）</h3><p>委托类需提供<code>getValue</code>函数和<code>setValue</code>函数，参数要求：</p>
<ul>
<li><code>thisRef</code>：第一个参数，同<code>getValue</code>对应的参数</li>
<li><code>property</code>：第二个参数，同<code>getValue</code>对应的参数</li>
<li>新增(<code>new value</code>)：第三个参数，类型必须跟属性一样或其父类型。</li>
</ul>
<p><code>getValue()</code> 和<code>setValue()</code>函数可以作为委托类的成员函数或者扩展函数来使用。 当需要委托一个属性给一个不是原来就提供这些函数的对象的时候，后者更为方便。</p>
<blockquote>
<p>两种函数都需要用<code>operator</code>关键字修饰。</p>
</blockquote>
<h3 id="接口"><a href="#接口" class="headerlink" title="接口"></a>接口</h3><p>委托类可以实现<code>ReadOnlyPropery</code>和<code>ReadWriteProperty</code>接口中的带<code>operator</code>的方法，这些接口在Kotlin标准库中声明：<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">interface</span> <span class="title">ReadOnlyProperty</span>&lt;<span class="type">in R, out T</span>&gt; </span>&#123;</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">getValue</span><span class="params">(thisRef: <span class="type">R</span>, property: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: T</div><div class="line">&#125;</div><div class="line"></div><div class="line"><span class="class"><span class="keyword">interface</span> <span class="title">ReadWriteProperty</span>&lt;<span class="type">in R, T</span>&gt; </span>&#123;</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">getValue</span><span class="params">(thisRef: <span class="type">R</span>, property: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: T</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">setValue</span><span class="params">(thisRef: <span class="type">R</span>, property: <span class="type">KProperty</span>&lt;*&gt;, value: <span class="type">T</span>)</span></span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<h3 id="提供委托（自-1-1-起）"><a href="#提供委托（自-1-1-起）" class="headerlink" title="提供委托（自 1.1 起）"></a>提供委托（自 1.1 起）</h3><p><code>provideDelegate</code>为提供委托，它可以为属性提供对象委托逻辑，可能的使用场景是在创建属性时（而不仅在其 <code>getter</code> 或 <code>setter</code> 中）检查属性一致性。<br><code>provideDelegate</code> 的参数与 <code>getValue</code> 相同：</p>
<ul>
<li><code>thisRef</code> —— 必须与属性所有者类型（对于扩展属性——指被扩展的类型）相同或者是它的超类型。</li>
<li><code>property</code> —— 必须是类型 <code>KProperty&lt;*&gt;</code> 或其超类。</li>
</ul>
<p>例如，在绑定之前检查属性名称：<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ResourceLoader</span></span>(resId: ResourceID) &#123;</div><div class="line">    <span class="keyword">operator</span> <span class="function"><span class="keyword">fun</span> <span class="title">provideDelegate</span><span class="params">(thisRef: <span class="type">MyUI</span>, prop: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: ReadOnlyProperty&lt;MyUI, String&gt; &#123;</div><div class="line">        checkProperty(thisRef, prop.name)</div><div class="line">        <span class="comment">// 创建委托</span></div><div class="line">    &#125;</div><div class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">fun</span> <span class="title">checkProperty</span><span class="params">(thisRef: <span class="type">MyUI</span>, name: <span class="type">String</span>)</span></span> &#123;</div><div class="line">    &#125;</div><div class="line">&#125;</div><div class="line"><span class="function"><span class="keyword">fun</span> MyUI.<span class="title">bindResource</span><span class="params">(id: <span class="type">ResourceID</span>)</span></span>: ResourceLoader &#123;</div><div class="line">    <span class="keyword">return</span> ResourceLoader(id)</div><div class="line">&#125;</div><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyUI</span> </span>&#123;</div><div class="line">    <span class="keyword">val</span> image <span class="keyword">by</span> bindResource(ResourceID.image_id) <span class="comment">//bindResource()产生委托对象</span></div><div class="line">    <span class="keyword">val</span> text <span class="keyword">by</span> bindResource(ResourceID.text_id)</div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>在创建 <code>MyUI</code> 实例期间，为每个属性调用<code>provideDelegate</code>方法，并立即执行必要的验证。</p>
<p>如果没有这种拦截属性与其委托之间的绑定的能力，为了实现相同的功能， 你必须显式传递属性名：<br><figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">MyUI</span> </span>&#123;</div><div class="line">    <span class="keyword">val</span> image <span class="keyword">by</span> bindResource(ResourceID.image_id, <span class="string">"image"</span>)</div><div class="line">    <span class="keyword">val</span> text <span class="keyword">by</span> bindResource(ResourceID.text_id, <span class="string">"text"</span>)</div><div class="line">&#125;</div><div class="line"><span class="function"><span class="keyword">fun</span> <span class="type">&lt;T&gt;</span> MyUI.<span class="title">bindResource</span><span class="params">(</span></span></div><div class="line"><span class="function"><span class="params">    id: <span class="type">ResourceID</span>&lt;<span class="type">T</span>&gt;,</span></span></div><div class="line"><span class="function"><span class="params">    propertyName: <span class="type">String</span></span></span></div><div class="line"><span class="function"><span class="params">    )</span></span>: ReadOnlyProperty&lt;MyUI, T&gt; &#123;</div><div class="line">        checkProperty(<span class="keyword">this</span>, propertyName)</div><div class="line">        <span class="comment">// 创建委托</span></div><div class="line">&#125;</div></pre></td></tr></table></figure></p>
<p>由于暂时没用的这个提供委托，所以在这里也不过多的介绍，上面是官网的一个栗子。</p>
<h2 id="一个委托实例"><a href="#一个委托实例" class="headerlink" title="一个委托实例"></a>一个委托实例</h2><p>下面来看一个自定义的<code>Delegate</code>，用来访问<code>SharedPreference</code>，这段代码是<code>Kotlin for Android Developer</code>的示例：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div><div class="line">9</div><div class="line">10</div><div class="line">11</div><div class="line">12</div><div class="line">13</div><div class="line">14</div><div class="line">15</div><div class="line">16</div><div class="line">17</div><div class="line">18</div><div class="line">19</div><div class="line">20</div><div class="line">21</div><div class="line">22</div><div class="line">23</div><div class="line">24</div><div class="line">25</div><div class="line">26</div><div class="line">27</div><div class="line">28</div><div class="line">29</div><div class="line">30</div><div class="line">31</div><div class="line">32</div><div class="line">33</div><div class="line">34</div><div class="line">35</div><div class="line">36</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">Preference</span>&lt;<span class="type">T</span>&gt;</span>(<span class="keyword">val</span> context: Context, <span class="keyword">val</span> name: String, <span class="keyword">val</span> <span class="keyword">default</span>: T) : ReadWriteProperty&lt;Any?, T&gt; &#123;</div><div class="line"></div><div class="line">    <span class="keyword">val</span> prefs <span class="keyword">by</span> lazy &#123; context.getSharedPreferences(<span class="string">"default"</span>, Context.MODE_PRIVATE) &#125;</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">getValue</span><span class="params">(thisRef: <span class="type">Any</span>?, property: <span class="type">KProperty</span>&lt;*&gt;)</span></span>: T &#123;</div><div class="line">        <span class="keyword">return</span> findPreference(name, <span class="keyword">default</span>)</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">override</span> <span class="function"><span class="keyword">fun</span> <span class="title">setValue</span><span class="params">(thisRef: <span class="type">Any</span>?, property: <span class="type">KProperty</span>&lt;*&gt;, value: <span class="type">T</span>)</span></span> &#123;</div><div class="line">        putPreference(name, value)</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">fun</span> <span class="type">&lt;U&gt;</span> <span class="title">findPreference</span><span class="params">(name: <span class="type">String</span>, <span class="keyword">default</span>: <span class="type">U</span>)</span></span>: U = with(prefs) &#123;</div><div class="line">        <span class="keyword">val</span> res: Any = <span class="keyword">when</span> (<span class="keyword">default</span>) &#123;</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Long</span> -&gt; getLong(name, <span class="keyword">default</span>)</div><div class="line">            <span class="keyword">is</span> String -&gt; getString(name, <span class="keyword">default</span>)</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Int</span> -&gt; getInt(name, <span class="keyword">default</span>)</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Boolean</span> -&gt; getBoolean(name, <span class="keyword">default</span>)</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Float</span> -&gt; getFloat(name, <span class="keyword">default</span>)</div><div class="line">            <span class="keyword">else</span> -&gt; <span class="keyword">throw</span> IllegalArgumentException(<span class="string">"This type can be saved into Preferences"</span>)</div><div class="line">        &#125;</div><div class="line"></div><div class="line">        res <span class="keyword">as</span> U</div><div class="line">    &#125;</div><div class="line"></div><div class="line">    <span class="keyword">private</span> <span class="function"><span class="keyword">fun</span> <span class="type">&lt;U&gt;</span> <span class="title">putPreference</span><span class="params">(name: <span class="type">String</span>, value: <span class="type">U</span>)</span></span> = with(prefs.edit()) &#123;</div><div class="line">        <span class="keyword">when</span> (value) &#123;</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Long</span> -&gt; putLong(name, value)</div><div class="line">            <span class="keyword">is</span> String -&gt; putString(name, value)</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Int</span> -&gt; putInt(name, value)</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Boolean</span> -&gt; putBoolean(name, value)</div><div class="line">            <span class="keyword">is</span> <span class="built_in">Float</span> -&gt; putFloat(name, value)</div><div class="line">            <span class="keyword">else</span> -&gt; <span class="keyword">throw</span> IllegalArgumentException(<span class="string">"This type can be saved into Preferences"</span>)</div><div class="line">        &#125;.apply()</div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>使用的时候：</p>
<figure class="highlight kotlin"><table><tr><td class="gutter"><pre><div class="line">1</div><div class="line">2</div><div class="line">3</div><div class="line">4</div><div class="line">5</div><div class="line">6</div><div class="line">7</div><div class="line">8</div></pre></td><td class="code"><pre><div class="line"><span class="class"><span class="keyword">class</span> <span class="title">ExampleActivity</span> : <span class="type">AppCompatActivity</span></span>()&#123;</div><div class="line">    <span class="keyword">var</span> a: <span class="built_in">Int</span> <span class="keyword">by</span> Preference(<span class="keyword">this</span>, <span class="string">"a"</span>, <span class="number">0</span>)</div><div class="line">    </div><div class="line">    <span class="function"><span class="keyword">fun</span> <span class="title">whatever</span><span class="params">()</span></span>&#123;</div><div class="line">        println(a)<span class="comment">//会从SharedPreference取这个数据</span></div><div class="line">        aInt = <span class="number">9</span> <span class="comment">//会将这个数据写入SharedPreference</span></div><div class="line">    &#125;</div><div class="line">&#125;</div></pre></td></tr></table></figure>
<p>这样就很方便了，再也不用去重复写<code>getSharedPreference()</code>、<code>commit()</code>、<code>edit()</code>、<code>apply()</code>之类的东西了。</p>

      
    </div>
    
    
    

    

    

    
      <div>
        <ul class="post-copyright">
  <li class="post-copyright-author">
    <strong>本文作者：</strong>
    Jowan
  </li>
  <li class="post-copyright-link">
    <strong>本文链接：</strong>
    <a href="http://www.jowanxu.top/2017/11/22/Kotlin学习_委托模式和委托属性/" title="Kotlin学习_委托模式（Delegate）和委托属性（Delegate Properties）">http://www.jowanxu.top/2017/11/22/Kotlin学习_委托模式和委托属性/</a>
  </li>
  <li class="post-copyright-license">
    <strong>版权声明： </strong>
    本博客所有文章除特别声明外，均采用 <a href="https://creativecommons.org/licenses/by-nc-sa/4.0/" rel="external nofollow" target="_blank">CC BY-NC-SA 4.0</a> 许可协议。转载请注明出处！
  </li>
</ul>

      </div>
    

    <footer class="post-footer">
      
        <div class="post-tags">
          
            <a href="/tags/Kotlin/" rel="tag"><i class="fa fa-tag"></i> Kotlin</a>
          
            <a href="/tags/Delegate/" rel="tag"><i class="fa fa-tag"></i> Delegate</a>
          
            <a href="/tags/Propertie/" rel="tag"><i class="fa fa-tag"></i> Propertie</a>
          
            <a href="/tags/Observable/" rel="tag"><i class="fa fa-tag"></i> Observable</a>
          
            <a href="/tags/Lazy/" rel="tag"><i class="fa fa-tag"></i> Lazy</a>
          
            <a href="/tags/Map/" rel="tag"><i class="fa fa-tag"></i> Map</a>
          
        </div>
      

      
      
      

      
        <div class="post-nav">
          <div class="post-nav-next post-nav-item">
            
              <a href="/2017/11/15/Kotlin学习_运算符重载/" rel="next" title="Kotlin学习_运算符重载">
                <i class="fa fa-chevron-left"></i> Kotlin学习_运算符重载
              </a>
            
          </div>

          <span class="post-nav-divider"></span>

          <div class="post-nav-prev post-nav-item">
            
              <a href="/2017/11/29/Kotlin_属性引发的方法数问题/" rel="prev" title="Kotlin_属性引发的方法数问题">
                Kotlin_属性引发的方法数问题 <i class="fa fa-chevron-right"></i>
              </a>
            
          </div>
        </div>
      

      
      
    </footer>
  </div>
  
  
  
  </article>



    <div class="post-spread">
      
    </div>
  </div>


          </div>
          


          
  <div class="comments" id="comments">
    
      <div id="lv-container" data-id="city" data-uid="MTAyMC8zMjA1My84NjE3"></div>
    
  </div>


        </div>
        
          
  
  <div class="sidebar-toggle">
    <div class="sidebar-toggle-line-wrap">
      <span class="sidebar-toggle-line sidebar-toggle-line-first"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-middle"></span>
      <span class="sidebar-toggle-line sidebar-toggle-line-last"></span>
    </div>
  </div>

  <aside id="sidebar" class="sidebar">
    
    <div class="sidebar-inner">

      

      
        <ul class="sidebar-nav motion-element">
          <li class="sidebar-nav-toc sidebar-nav-active" data-target="post-toc-wrap" >
            文章目录
          </li>
          <li class="sidebar-nav-overview" data-target="site-overview">
            站点概览
          </li>
        </ul>
      

      <section class="site-overview sidebar-panel">
        <div class="site-author motion-element" itemprop="author" itemscope itemtype="http://schema.org/Person">
          <img class="site-author-image" itemprop="image"
               src="/images/avatar.gif"
               alt="Jowan" />
          <p class="site-author-name" itemprop="name">Jowan</p>
           
              <p class="site-description motion-element" itemprop="description">叫我旺仔<br/>Android Developer</p>
          
        </div>
        <nav class="site-state motion-element">

          
            <div class="site-state-item site-state-posts">
              <a href="/archives/">
                <span class="site-state-item-count">31</span>
                <span class="site-state-item-name">日志</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-categories">
              <a href="/categories/index.html">
                <span class="site-state-item-count">5</span>
                <span class="site-state-item-name">分类</span>
              </a>
            </div>
          

          
            
            
            <div class="site-state-item site-state-tags">
              <a href="/tags/index.html">
                <span class="site-state-item-count">27</span>
                <span class="site-state-item-name">标签</span>
              </a>
            </div>
          

        </nav>

        
          <div class="feed-link motion-element">
            <a href="/atom.xml" rel="alternate">
              <i class="fa fa-rss"></i>
              RSS
            </a>
          </div>
        

        <div class="links-of-author motion-element">
          
            
              <span class="links-of-author-item">
                <a href="https://plus.google.com/u/0/111824269044709365866" target="_blank" title="Google">
                  
                    
                      Google
                    
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="https://github.com/wangzailfm" target="_blank" title="GitHub">
                  
                    
                      GitHub
                    
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="http://weibo.com/809077554" target="_blank" title="微博">
                  
                    
                      微博
                    
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="673173629@qq.com" target="_blank" title="E-Mail">
                  
                    
                      E-Mail
                    
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="http://blog.csdn.net/u011976726" target="_blank" title="CSDN">
                  
                    
                      CSDN
                    
                </a>
              </span>
            
              <span class="links-of-author-item">
                <a href="http://www.jianshu.com/u/5509a21c1623" target="_blank" title="简书">
                  
                    
                      简书
                    
                </a>
              </span>
            
          
        </div>

        
        

        
        
          <div class="links-of-blogroll motion-element links-of-blogroll-block">
            <div class="links-of-blogroll-title">
              <i class="fa  fa-fw fa-globe"></i>
              Links
            </div>
            <ul class="links-of-blogroll-list">
              
                <li class="links-of-blogroll-item">
                  <a href="http://wanandroid.com/" title="WanAndroid" target="_blank">WanAndroid</a>
                </li>
              
            </ul>
          </div>
        

        


      </section>

      
      <!--noindex-->
        <section class="post-toc-wrap motion-element sidebar-panel sidebar-panel-active">
          <div class="post-toc">

            
              
            

            
              <div class="post-toc-content"><ol class="nav"><li class="nav-item nav-level-2"><a class="nav-link" href="#委托模式-Delegate"><span class="nav-number">1.</span> <span class="nav-text">委托模式(Delegate)</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#类委托"><span class="nav-number">1.1.</span> <span class="nav-text">类委托</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#委托属性-Delegate-Properties"><span class="nav-number">2.</span> <span class="nav-text">委托属性(Delegate Properties)</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#委托标准"><span class="nav-number">2.1.</span> <span class="nav-text">委托标准</span></a><ol class="nav-child"><li class="nav-item nav-level-4"><a class="nav-link" href="#延迟属性-Lazy"><span class="nav-number">2.1.1.</span> <span class="nav-text">延迟属性 Lazy</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#可观察属性-Observable"><span class="nav-number">2.1.2.</span> <span class="nav-text">可观察属性 Observable</span></a></li><li class="nav-item nav-level-4"><a class="nav-link" href="#Map委托属性-Storing-Properties-in-a-Map"><span class="nav-number">2.1.3.</span> <span class="nav-text">Map委托属性(Storing Properties in a Map)</span></a></li></ol></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#局部委托属性（1-1-起）"><span class="nav-number">3.</span> <span class="nav-text">局部委托属性（1.1 起）</span></a></li><li class="nav-item nav-level-2"><a class="nav-link" href="#委托属性要求"><span class="nav-number">4.</span> <span class="nav-text">委托属性要求</span></a><ol class="nav-child"><li class="nav-item nav-level-3"><a class="nav-link" href="#只读属性（read-only，使用val定义）"><span class="nav-number">4.1.</span> <span class="nav-text">只读属性（read-only，使用val定义）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#可变属性（mutable，使用var定义）"><span class="nav-number">4.2.</span> <span class="nav-text">可变属性（mutable，使用var定义）</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#接口"><span class="nav-number">4.3.</span> <span class="nav-text">接口</span></a></li><li class="nav-item nav-level-3"><a class="nav-link" href="#提供委托（自-1-1-起）"><span class="nav-number">4.4.</span> <span class="nav-text">提供委托（自 1.1 起）</span></a></li></ol></li><li class="nav-item nav-level-2"><a class="nav-link" href="#一个委托实例"><span class="nav-number">5.</span> <span class="nav-text">一个委托实例</span></a></li></ol></div>
            

          </div>
        </section>
      <!--/noindex-->
      

      

    </div>
  </aside>


        
      </div>
    </main>

    <footer id="footer" class="footer">
      <div class="footer-inner">
        <div class="copyright" >
  
  &copy; 
  <span itemprop="copyrightYear">2017</span>
  <span class="with-love">
    <i class="fa fa-heart"></i>
  </span>
  <span class="author" itemprop="copyrightHolder">Jowan</span>
</div>


<div class="powered-by">
  由 <a class="theme-link" href="https://hexo.io">Hexo</a> 强力驱动
</div>

<div class="theme-info">
  主题 -
  <a class="theme-link" href="https://github.com/iissnan/hexo-theme-next">
    NexT.Gemini
  </a>
</div>


        
<div class="busuanzi-count">
  <script async src="https://dn-lbstatics.qbox.me/busuanzi/2.3/busuanzi.pure.mini.js"></script>

  
    <span class="site-uv">
      <i class="fa fa-user">本站访客数</i>
      <span class="busuanzi-value" id="busuanzi_value_site_uv"></span>
      人次
    </span>
  

  
    <span class="site-pv">
      <i class="fa fa-eye">本站总访问量</i>
      <span class="busuanzi-value" id="busuanzi_value_site_pv"></span>
      次
    </span>
  
</div>


        
      </div>
    </footer>

    
      <div class="back-to-top">
        <i class="fa fa-arrow-up"></i>
        
      </div>
    

  </div>

  

<script type="text/javascript">
  if (Object.prototype.toString.call(window.Promise) !== '[object Function]') {
    window.Promise = null;
  }
</script>









  












  
  <script type="text/javascript" src="/lib/jquery/index.js?v=2.1.3"></script>

  
  <script type="text/javascript" src="/lib/fastclick/lib/fastclick.min.js?v=1.0.6"></script>

  
  <script type="text/javascript" src="/lib/jquery_lazyload/jquery.lazyload.js?v=1.9.7"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/velocity/velocity.ui.min.js?v=1.2.1"></script>

  
  <script type="text/javascript" src="/lib/fancybox/source/jquery.fancybox.pack.js?v=2.1.5"></script>


  


  <script type="text/javascript" src="/js/src/utils.js?v=5.1.2"></script>

  <script type="text/javascript" src="/js/src/motion.js?v=5.1.2"></script>



  
  


  <script type="text/javascript" src="/js/src/affix.js?v=5.1.2"></script>

  <script type="text/javascript" src="/js/src/schemes/pisces.js?v=5.1.2"></script>



  
  <script type="text/javascript" src="/js/src/scrollspy.js?v=5.1.2"></script>
<script type="text/javascript" src="/js/src/post-details.js?v=5.1.2"></script>



  


  <script type="text/javascript" src="/js/src/bootstrap.js?v=5.1.2"></script>



  


  




	





  





  
    <script type="text/javascript">
      (function(d, s) {
        var j, e = d.getElementsByTagName(s)[0];
        if (typeof LivereTower === 'function') { return; }
        j = d.createElement(s);
        j.src = 'https://cdn-city.livere.com/js/embed.dist.js';
        j.async = true;
        e.parentNode.insertBefore(j, e);
      })(document, 'script');
    </script>
  






  

  <script type="text/javascript">
    // Popup Window;
    var isfetched = false;
    var isXml = true;
    // Search DB path;
    var search_path = "search.xml";
    if (search_path.length === 0) {
      search_path = "search.xml";
    } else if (/json$/i.test(search_path)) {
      isXml = false;
    }
    var path = "/" + search_path;
    // monitor main search box;

    var onPopupClose = function (e) {
      $('.popup').hide();
      $('#local-search-input').val('');
      $('.search-result-list').remove();
      $('#no-result').remove();
      $(".local-search-pop-overlay").remove();
      $('body').css('overflow', '');
    }

    function proceedsearch() {
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay"></div>')
        .css('overflow', 'hidden');
      $('.search-popup-overlay').click(onPopupClose);
      $('.popup').toggle();
      var $localSearchInput = $('#local-search-input');
      $localSearchInput.attr("autocapitalize", "none");
      $localSearchInput.attr("autocorrect", "off");
      $localSearchInput.focus();
    }

    // search function;
    var searchFunc = function(path, search_id, content_id) {
      'use strict';

      // start loading animation
      $("body")
        .append('<div class="search-popup-overlay local-search-pop-overlay">' +
          '<div id="search-loading-icon">' +
          '<i class="fa fa-spinner fa-pulse fa-5x fa-fw"></i>' +
          '</div>' +
          '</div>')
        .css('overflow', 'hidden');
      $("#search-loading-icon").css('margin', '20% auto 0 auto').css('text-align', 'center');

      $.ajax({
        url: path,
        dataType: isXml ? "xml" : "json",
        async: true,
        success: function(res) {
          // get the contents from search data
          isfetched = true;
          $('.popup').detach().appendTo('.header-inner');
          var datas = isXml ? $("entry", res).map(function() {
            return {
              title: $("title", this).text(),
              content: $("content",this).text(),
              url: $("url" , this).text()
            };
          }).get() : res;
          var input = document.getElementById(search_id);
          var resultContent = document.getElementById(content_id);
          var inputEventFunction = function() {
            var searchText = input.value.trim().toLowerCase();
            var keywords = searchText.split(/[\s\-]+/);
            if (keywords.length > 1) {
              keywords.push(searchText);
            }
            var resultItems = [];
            if (searchText.length > 0) {
              // perform local searching
              datas.forEach(function(data) {
                var isMatch = false;
                var hitCount = 0;
                var searchTextCount = 0;
                var title = data.title.trim();
                var titleInLowerCase = title.toLowerCase();
                var content = data.content.trim().replace(/<[^>]+>/g,"");
                var contentInLowerCase = content.toLowerCase();
                var articleUrl = decodeURIComponent(data.url);
                var indexOfTitle = [];
                var indexOfContent = [];
                // only match articles with not empty titles
                if(title != '') {
                  keywords.forEach(function(keyword) {
                    function getIndexByWord(word, text, caseSensitive) {
                      var wordLen = word.length;
                      if (wordLen === 0) {
                        return [];
                      }
                      var startPosition = 0, position = [], index = [];
                      if (!caseSensitive) {
                        text = text.toLowerCase();
                        word = word.toLowerCase();
                      }
                      while ((position = text.indexOf(word, startPosition)) > -1) {
                        index.push({position: position, word: word});
                        startPosition = position + wordLen;
                      }
                      return index;
                    }

                    indexOfTitle = indexOfTitle.concat(getIndexByWord(keyword, titleInLowerCase, false));
                    indexOfContent = indexOfContent.concat(getIndexByWord(keyword, contentInLowerCase, false));
                  });
                  if (indexOfTitle.length > 0 || indexOfContent.length > 0) {
                    isMatch = true;
                    hitCount = indexOfTitle.length + indexOfContent.length;
                  }
                }

                // show search results

                if (isMatch) {
                  // sort index by position of keyword

                  [indexOfTitle, indexOfContent].forEach(function (index) {
                    index.sort(function (itemLeft, itemRight) {
                      if (itemRight.position !== itemLeft.position) {
                        return itemRight.position - itemLeft.position;
                      } else {
                        return itemLeft.word.length - itemRight.word.length;
                      }
                    });
                  });

                  // merge hits into slices

                  function mergeIntoSlice(text, start, end, index) {
                    var item = index[index.length - 1];
                    var position = item.position;
                    var word = item.word;
                    var hits = [];
                    var searchTextCountInSlice = 0;
                    while (position + word.length <= end && index.length != 0) {
                      if (word === searchText) {
                        searchTextCountInSlice++;
                      }
                      hits.push({position: position, length: word.length});
                      var wordEnd = position + word.length;

                      // move to next position of hit

                      index.pop();
                      while (index.length != 0) {
                        item = index[index.length - 1];
                        position = item.position;
                        word = item.word;
                        if (wordEnd > position) {
                          index.pop();
                        } else {
                          break;
                        }
                      }
                    }
                    searchTextCount += searchTextCountInSlice;
                    return {
                      hits: hits,
                      start: start,
                      end: end,
                      searchTextCount: searchTextCountInSlice
                    };
                  }

                  var slicesOfTitle = [];
                  if (indexOfTitle.length != 0) {
                    slicesOfTitle.push(mergeIntoSlice(title, 0, title.length, indexOfTitle));
                  }

                  var slicesOfContent = [];
                  while (indexOfContent.length != 0) {
                    var item = indexOfContent[indexOfContent.length - 1];
                    var position = item.position;
                    var word = item.word;
                    // cut out 100 characters
                    var start = position - 20;
                    var end = position + 80;
                    if(start < 0){
                      start = 0;
                    }
                    if (end < position + word.length) {
                      end = position + word.length;
                    }
                    if(end > content.length){
                      end = content.length;
                    }
                    slicesOfContent.push(mergeIntoSlice(content, start, end, indexOfContent));
                  }

                  // sort slices in content by search text's count and hits' count

                  slicesOfContent.sort(function (sliceLeft, sliceRight) {
                    if (sliceLeft.searchTextCount !== sliceRight.searchTextCount) {
                      return sliceRight.searchTextCount - sliceLeft.searchTextCount;
                    } else if (sliceLeft.hits.length !== sliceRight.hits.length) {
                      return sliceRight.hits.length - sliceLeft.hits.length;
                    } else {
                      return sliceLeft.start - sliceRight.start;
                    }
                  });

                  // select top N slices in content

                  var upperBound = parseInt('1');
                  if (upperBound >= 0) {
                    slicesOfContent = slicesOfContent.slice(0, upperBound);
                  }

                  // highlight title and content

                  function highlightKeyword(text, slice) {
                    var result = '';
                    var prevEnd = slice.start;
                    slice.hits.forEach(function (hit) {
                      result += text.substring(prevEnd, hit.position);
                      var end = hit.position + hit.length;
                      result += '<b class="search-keyword">' + text.substring(hit.position, end) + '</b>';
                      prevEnd = end;
                    });
                    result += text.substring(prevEnd, slice.end);
                    return result;
                  }

                  var resultItem = '';

                  if (slicesOfTitle.length != 0) {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + highlightKeyword(title, slicesOfTitle[0]) + "</a>";
                  } else {
                    resultItem += "<li><a href='" + articleUrl + "' class='search-result-title'>" + title + "</a>";
                  }

                  slicesOfContent.forEach(function (slice) {
                    resultItem += "<a href='" + articleUrl + "'>" +
                      "<p class=\"search-result\">" + highlightKeyword(content, slice) +
                      "...</p>" + "</a>";
                  });

                  resultItem += "</li>";
                  resultItems.push({
                    item: resultItem,
                    searchTextCount: searchTextCount,
                    hitCount: hitCount,
                    id: resultItems.length
                  });
                }
              })
            };
            if (keywords.length === 1 && keywords[0] === "") {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-search fa-5x" /></div>'
            } else if (resultItems.length === 0) {
              resultContent.innerHTML = '<div id="no-result"><i class="fa fa-frown-o fa-5x" /></div>'
            } else {
              resultItems.sort(function (resultLeft, resultRight) {
                if (resultLeft.searchTextCount !== resultRight.searchTextCount) {
                  return resultRight.searchTextCount - resultLeft.searchTextCount;
                } else if (resultLeft.hitCount !== resultRight.hitCount) {
                  return resultRight.hitCount - resultLeft.hitCount;
                } else {
                  return resultRight.id - resultLeft.id;
                }
              });
              var searchResultList = '<ul class=\"search-result-list\">';
              resultItems.forEach(function (result) {
                searchResultList += result.item;
              })
              searchResultList += "</ul>";
              resultContent.innerHTML = searchResultList;
            }
          }

          if ('auto' === 'auto') {
            input.addEventListener('input', inputEventFunction);
          } else {
            $('.search-icon').click(inputEventFunction);
            input.addEventListener('keypress', function (event) {
              if (event.keyCode === 13) {
                inputEventFunction();
              }
            });
          }

          // remove loading animation
          $(".local-search-pop-overlay").remove();
          $('body').css('overflow', '');

          proceedsearch();
        }
      });
    }

    // handle and trigger popup window;
    $('.popup-trigger').click(function(e) {
      e.stopPropagation();
      if (isfetched === false) {
        searchFunc(path, 'local-search-input', 'local-search-result');
      } else {
        proceedsearch();
      };
    });

    $('.popup-btn-close').click(onPopupClose);
    $('.popup').click(function(e){
      e.stopPropagation();
    });
    $(document).on('keyup', function (event) {
      var shouldDismissSearchPopup = event.which === 27 &&
        $('.search-popup').is(':visible');
      if (shouldDismissSearchPopup) {
        onPopupClose();
      }
    });
  </script>





  

  

  

  

  

  

</body>
</html>
